package com.bsj.travel.forward.utils;

import lombok.extern.slf4j.Slf4j;
import okhttp3.*;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @author : zhuojie.c
 * @version V1.0
 * @Description: TODO
 * @date Date : 2022年06月29日
 */
@Slf4j
public class OkHttpUtil {

    private final OkHttpClient okHttpClient;

    // 默认配置参数
    private static final int MAX_IDLE_CONNECTIONS = 200;
    // 分钟
    private static final int KEEP_ALIVE_DURATION = 5;
    private static final int CONNECT_TIMEOUT_MS = 5000;
    private static final int READ_TIMEOUT_MS = 5000;
    private static final int WRITE_TIMEOUT_MS = 5000;
    private static final int RETRY_COUNT = 3;
    private static final TrustManager[] TRUST_MANAGERS = buildTrustManagers();

    public OkHttpUtil() {
        // 配置连接池
        ConnectionPool connectionPool = new ConnectionPool(MAX_IDLE_CONNECTIONS, KEEP_ALIVE_DURATION, TimeUnit.MINUTES);
        // 创建 OkHttpClient 实例，配置连接池、超时和重试机制
        this.okHttpClient = new OkHttpClient.Builder()
                .connectionPool(connectionPool)
                .connectTimeout(CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
                .readTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
                .writeTimeout(WRITE_TIMEOUT_MS, TimeUnit.MILLISECONDS)
                .sslSocketFactory(createSSLSocketFactory(TRUST_MANAGERS), (X509TrustManager) TRUST_MANAGERS[0])
                // 启用自动重试
                .retryOnConnectionFailure(true)
                .build();
    }


    /**
     * 生成安全套接字工厂，用于https请求的证书跳过
     *
     * @param trustAllCerts
     * @return
     */
    private static SSLSocketFactory createSSLSocketFactory(TrustManager[] trustAllCerts) {
        SSLSocketFactory ssfFactory = null;
        try {
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new SecureRandom());
            ssfFactory = sc.getSocketFactory();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ssfFactory;
    }

    private static TrustManager[] buildTrustManagers() {
        return new TrustManager[]{
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] chain, String authType) {
                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] chain, String authType) {
                    }

                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[]{};
                    }
                }
        };
    }


    /**
     * 发送 POST 请求
     *
     * @param url     请求 URL
     * @param headers 请求头
     * @param params  请求参数（表单格式）
     * @return 响应内容
     * @throws IOException 如果请求失败
     */
    public String doPost(String url, Map<String, String> headers, Map<String, String> params) throws IOException {
        FormBody.Builder formBuilder = new FormBody.Builder();
        if (params != null) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                formBuilder.add(entry.getKey(), entry.getValue());
            }
        }
        RequestBody requestBody = formBuilder.build();

        Request.Builder requestBuilder = new Request.Builder().url(url).post(requestBody);
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                requestBuilder.addHeader(entry.getKey(), entry.getValue());
            }
        }

        // 尝试发送请求并处理响应
        try (Response response = okHttpClient.newCall(requestBuilder.build()).execute()) {
            if (!response.isSuccessful()) throw new IOException("Unexpected code " + response.code());

            return response.body().string();
        } catch (IOException e) {
            // 自定义重试逻辑
            if (RETRY_COUNT > 0) {
                System.err.println("Request failed, retrying... (" + RETRY_COUNT + " attempts left)");
                // 递归调用进行重试
                return doPost(url, headers, params);
            } else {
                // 如果重试次数用尽，抛出异常
                throw e;
            }
        }
    }
}
